
/**
  ******************************************************************************
  * Copyright 2021 The grapilot Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       dev_mgr_spi.c
  * @author     baiyang
  * @date       2021-11-28
  ******************************************************************************
  */

/*----------------------------------include-----------------------------------*/
#include <stdio.h>
#include <string.h>

#include "dev_mgr_spi.h"

#include <rtthread.h>
#include <rtdevice.h>
/*-----------------------------------macro------------------------------------*/

/*----------------------------------typedef-----------------------------------*/

/*---------------------------------prototype----------------------------------*/
static bool _read_registers(gp_device_t dev, uint8_t first_reg, uint8_t *recv, uint32_t recv_len);
static bool _write_register(gp_device_t dev, uint8_t reg, uint8_t val, bool checked);
static bool _transfer(gp_device_t dev, const uint8_t *send, uint32_t send_len, uint8_t *recv, uint32_t recv_len);
static bool _take_bus(gp_device_t dev);
static bool _release_bus(gp_device_t dev);
/*----------------------------------variable----------------------------------*/
static struct device_bus spi_bus[4];    //

static struct devmgr_device_ops devmgr_spi_ops = {.read_registers = _read_registers,
                                                  .write_register = _write_register,
                                                  .transfer       = _transfer,
                                                  .take_bus       = _take_bus,
                                                  .release_bus    = _release_bus};
/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
/**
  * @brief       
  * @param[in]   dev  
  * @param[in]   devtype  
  * @param[out]  
  * @retval      
  * @note        
  */
void devmgr_config_spi_dev(gp_device_t dev)
{
    RT_ASSERT(dev != RT_NULL);

    uint8_t bus_id_index = 0;

    dev->ops = &devmgr_spi_ops;

    if (strstr(dev->dev->parent.name, "spi1") != NULL) {
        bus_id_index = 0;
    } else if (strstr(dev->dev->parent.name, "spi2") != NULL) {
        bus_id_index = 1;
    } else if (strstr(dev->dev->parent.name, "spi3") != NULL) {
        bus_id_index = 2;
    } else if (strstr(dev->dev->parent.name, "spi4") != NULL) {
        bus_id_index = 3;
    }

    dev->bus = &(spi_bus[bus_id_index]);
    dev->bus->bus_id = bus_id_index + 1;

    dev->d.devid_s.bus_type = BUS_TYPE_SPI;
    dev->d.devid_s.bus = dev->bus->bus_id;

    if (strcmp(dev->dev->parent.name , ICM20608_SPI_DEVICE_NAME) == 0) {
        dev->d.devid_s.address = ICM20608_SPI_DEVICE_ADDRESS;

        dev->spi_data_width = 8;
        dev->spi_mode = RT_SPI_MODE_3 | RT_SPI_MSB; /* SPI Compatible Modes 3 */
        dev->spi_freq_low = ICM20608_SPI_SPEED_LOW;
        dev->spi_freq_high = ICM20608_SPI_SPEED_HIGH;
    }

    if (strcmp(dev->dev->parent.name , MPU9250_SPI_DEVICE_NAME) == 0) {
        dev->d.devid_s.address = MPU9250_SPI_DEVICE_ADDRESS;

        dev->spi_data_width = 8;
        dev->spi_mode = RT_SPI_MODE_3 | RT_SPI_MSB; /* SPI Compatible Modes 3 */
        dev->spi_freq_low = MPU9250_SPI_SPEED_LOW;
        dev->spi_freq_high = MPU9250_SPI_SPEED_HIGH;
    }

    if (strcmp(dev->dev->parent.name , MPU60x0_SPI_DEVICE_NAME) == 0) {
        dev->d.devid_s.address = MPU60x0_SPI_DEVICE_ADDRESS;

        dev->spi_data_width = 8;
        dev->spi_mode = RT_SPI_MODE_3 | RT_SPI_MSB; /* SPI Compatible Modes 3 */
        dev->spi_freq_low = MPU60x0_SPI_SPEED_LOW;
        dev->spi_freq_high = MPU60x0_SPI_SPEED_HIGH;
    }

    if (strcmp(dev->dev->parent.name , L3GD20H_SPI_DEVICE_NAME) == 0) {
        dev->d.devid_s.address = L3GD20H_SPI_DEVICE_ADDRESS;

        dev->spi_data_width = 8;
        dev->spi_mode = RT_SPI_MODE_3 | RT_SPI_MSB; /* SPI Compatible Modes 3 */
        dev->spi_freq_low = L3GD20H_SPI_SPEED_LOW;
        dev->spi_freq_high = L3GD20H_SPI_SPEED_HIGH;
    }

    if (strcmp(dev->dev->parent.name , MS5611_SPI_DEVICE_NAME) == 0) {
        dev->d.devid_s.address = MS5611_SPI_DEVICE_ADDRESS;

        dev->spi_data_width = 8;
        dev->spi_mode = RT_SPI_MODE_3 | RT_SPI_MSB; /* SPI Compatible Modes 3 */
        dev->spi_freq_low = MS5611_SPI_SPEED_LOW;
        dev->spi_freq_high = MS5611_SPI_SPEED_HIGH;
    }

    if (strcmp(dev->dev->parent.name , LSM9DS0_SPI_DEVICE_NAME) == 0) {
        dev->d.devid_s.address = LSM9DS0_SPI_DEVICE_ADDRESS;

        dev->spi_data_width = 8;
        dev->spi_mode = RT_SPI_MODE_3 | RT_SPI_MSB; /* SPI Compatible Modes 3 */
        dev->spi_freq_low = LSM9DS0_SPI_SPEED_LOW;
        dev->spi_freq_high = LSM9DS0_SPI_SPEED_HIGH;
    }

    devmgr_set_speed(dev, DEV_SPEED_LOW);
}

/**
 * Wrapper function over #transfer() to read recv_len registers, starting
 * by first_reg, into the array pointed by recv. The read flag passed to
 * #set_read_flag(uint8_t) is ORed with first_reg before performing the
 * transfer.
 *
 * Return: true on a successful transfer, false on failure.
 */
static bool _read_registers(gp_device_t dev, uint8_t first_reg, uint8_t *recv, uint32_t recv_len)
{
    rt_err_t res = RT_ERROR;

    first_reg |= dev->_read_flag;
    res = rt_spi_send_then_recv((struct rt_spi_device*)dev->dev, (void*)&first_reg, 1, (void*)recv, recv_len);

    return (res == RT_EOK);
}

/**
 * Wrapper function over #transfer() to write a byte to the register reg.
 * The transfer is done by sending reg and val in that order.
 *
 * Return: true on a successful transfer, false on failure.
 */
static bool _write_register(gp_device_t dev, uint8_t reg, uint8_t val, bool checked)
{
    bool res = false;
    uint8_t buf[2] = { reg, val };

    if (checked) {
        devmgr_set_checked_register(dev, reg, val);
    }

    res = rt_spi_send_then_recv((struct rt_spi_device*)dev->dev, buf, sizeof(buf), NULL, 0);

    return (res == RT_EOK);
}

/**
  * @brief       
  * @param[in]   dev  
  * @param[in]   send  
  * @param[in]   send_len  
  * @param[in]   recv  
  * @param[in]   recv_len  
  * @param[out]  
  * @retval      
  * @note        
  */
static bool _transfer(gp_device_t dev, const uint8_t *send, uint32_t send_len, uint8_t *recv, uint32_t recv_len)
{
    bool res = false;

    if (recv == NULL) {
        //TODO: 逻辑有些混乱，需改进
        res = (rt_spi_transfer((struct rt_spi_device*)dev->dev, send, recv, send_len) == 0);
    } else {
        res = rt_spi_send_then_recv((struct rt_spi_device*)dev->dev, send, send_len, recv, recv_len);
    }

    return (res == RT_EOK);
}

/**
  * @brief       
  * @param[in]   dev  
  * @param[out]  
  * @retval      
  * @note        
  */
static bool _take_bus(gp_device_t dev)
{
    struct rt_spi_device *device = (struct rt_spi_device *)dev->dev;
    rt_err_t res = rt_mutex_take(&device->bus->lock, RT_WAITING_FOREVER);

    return res == RT_EOK;
}

/**
  * @brief       
  * @param[in]   dev  
  * @param[out]  
  * @retval      
  * @note        
  */
static bool _release_bus(gp_device_t dev)
{
    struct rt_spi_device *device = (struct rt_spi_device *)dev->dev;
    rt_err_t res = rt_mutex_release(&device->bus->lock);

    return res == RT_EOK;
}

/*------------------------------------test------------------------------------*/


